package com.xigege.nio.bufferAndChannel;

import com.xigege.nio.bufferAndChannel.util.ByteBufferUtil;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.charset.StandardCharsets;

/**
 * 举例说明buffer的使用（简单使用)
 */
public class BasicBuffer {
    public static void main(String[] args) throws IOException {
        testBufferExam();
    }

    /**
     * 处理黏包和半包
     */
    private static void testBufferExam() {
        ByteBuffer buffer = ByteBuffer.allocate(32);
        buffer.put("Hello,world\nI'm zhangsan\nHo".getBytes());
        split(buffer);
        buffer.put("w are you?\n".getBytes());
        split(buffer);
    }
    /**
     * 分割
     */
    private static void split(ByteBuffer source) {
        source.flip();
        for (int i = 0; i < source.limit(); i++) {
            if (source.get(i) == '\n') {
                int length= i + 1 - source.position();
                ByteBuffer target = ByteBuffer.allocate(length);
                for (int j = 0; j < length; j++) {
                    target.put(source.get());
                }
                ByteBufferUtil.debugAll(target);
            }
        }
        source.compact();
    }

    /**
     * 测试ByteBuffer和String的相互转换
     */
    private static void testStringByteBuffer() {
        // string 2 ByteBuffer
        // string --> getBytes()
        ByteBuffer buffer1 = ByteBuffer.allocate(16);
        buffer1.put("hello world".getBytes());
        ByteBufferUtil.debugAll(buffer1);

        // StandardCharsets
        // 使用Charsets的方式会直接变成读模式，此时position = 0;
        ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello world");
        ByteBufferUtil.debugAll(buffer2);

        // wrap
        ByteBuffer buffer3 = ByteBuffer.wrap("hello".getBytes());
        ByteBufferUtil.debugAll(buffer3);

        // ByteBuffer 2 string
        String string2 = StandardCharsets.UTF_8.decode(buffer2).toString();
        System.out.println(string2);

        buffer1.flip();
        String string1 = StandardCharsets.UTF_8.decode(buffer1).toString();
        System.out.println(string1);
    }

    /**
     * 测试Buffer的mark和reset方法
     */
    private static void testMarkAndReset() {
        ByteBuffer buffer = ByteBuffer.allocate(16);
        buffer.put(new byte[]{'q', 'w', 'e', 'r', '1', '2'});
        buffer.flip();
        // markAndReset
        System.out.println((char) buffer.get());
        System.out.println((char) buffer.get());
        buffer.mark();
        System.out.println((char) buffer.get());
        System.out.println((char) buffer.get());
        buffer.reset();
        System.out.println((char) buffer.get());
        System.out.println((char) buffer.get());

        // 重头开始读，position=0;
        buffer.rewind();

        // 不会改变position的读指针
        //get(i)
        System.out.println(buffer.get(2));
        ByteBufferUtil.debugAll(buffer);
    }

    /**
     * 测试分配内存的方法
     */
    private static void allocateMemory() {
        // 堆内存，读写效率略低
        ByteBuffer.allocate(16);
        // 直接内存，少一次拷贝，读写效率略高一点
        // 但是难以回收内存，可能造成内存泄漏
        ByteBuffer.allocateDirect(16);
    }


    private static void testByteBuffer() {
        ByteBuffer buffer = ByteBuffer.allocate(16);
        byte[] bytes = {1, 2, 91, 78, 22};
        buffer.put(bytes);
        buffer.flip();
        for (byte i = 0; i < 2; i++) {
            System.out.println(buffer.get());
            // 从头开始读
            buffer.rewind();
        }
        System.out.println(buffer.get());
        buffer.clear();
        // 若是没有读取完，会将未读完的数据往前压
        // position指针指向未读完的数据的下一位
        buffer.compact();
        ByteBufferUtil.debugAll(buffer);
    }

    private static void testIntBuffer() {
        // 创建一个buffer，大小为5，即可以存放5个int；
        IntBuffer intBuffer = IntBuffer.allocate(5);

        //向buffer存放数据
        for (int i = 0; i < intBuffer.capacity(); i++) {
            intBuffer.put(i << 2);
        }

        //如何从buffer读取数据
        //将buffer转换，读写切换；
        intBuffer.flip();

        while (intBuffer.hasRemaining()) {
            System.out.println(intBuffer.get());
        }
    }
}
